APPLICATION FRAMEWORK FOR PSION SERIES 3 By John Hind ---------------------------------------------------------------------- A Dynamic Link Library that supports message-based, event-driven application programming in OPL on the PSION Series 3 or Series 3a pocket computers. The library includes support for time-based applications that cannot otherwise be done without machine code. Full documentation, source code and a test application is included. ---------------------------------------------------------------------- FEATURE LIST * Automatic handling of all Series3 and 3a operating system messages. * Automatic vectoring of hotkey and menu options to application code. * Simple file handling procedures automatically work from system level. * Non-blocking keyboard handling with all key combinations available. * Support for "lazy" screen updating for better responsiveness. * Non-blocking seconds timer with elapsed seconds count. * Non-blocking minutes timer synchronised to real-time clock and with elapsed minutes count. * Message masking for simple mode handling. * Automatic error handling mechanisms. * Application exit interlock works from all exit methods. * Dynamic Link Library may be shared amongst multiple applications. * Includes fix for bug in the MENU command documented by PSION. ---------------------------------------------------------------------- NEW FEATURES IN VERSION 3 * Fully tested to work with both Series 3 and Series 3a. * Supports the new S3a DATE CHANGE message. * Now supports +,-,/ and * as Hotkeys. * Now supports shifted Hotkeys. * New Customisation and Internationalisation features. * More robust system error handling to prevent deadlocks. * Support for application asynchronous I/O. ---------------------------------------------------------------------- OVERVIEW The library provides a main routine which runs, after initialisation, until the application terminates. This routine invokes call-back routines supplied by the application programmer when system, keyboard or timer messages occur. The library also supplies a number of utility routines that can be called from the call-back routines. ---------------------------------------------------------------------- FIRST LOOK The distribution archive contains the following files: FRAMELIB.OPO - Translated framework module (S3 or S3a). FRAMELBA.OPO - Translated framework module (S3a only). FRAMELIB.OPL - Commented framework source code. FTEST.OPL - Source code for example & test program. FRAMELIB.TXT - This file. SAMPLE.TXT - Annotated source code from a real-world application. To run the example program, first copy FRAMELIB.OPO into an \OPO directory on your S3. Then copy FTEST.OPL into the \OPL directory, open it and translate. On completion, install using PSION-I at the system screen. Note that the sample application uses the OPL files in the OPL directory an a convenient example. It will not actually open or modify any files. The test application simply displays messages and parameters as events occur. Use the [Menu] key to see the available facilities. Try pressing keys, switching the S3 on and off, opening new files at the system level etc. Examine the FTEST.OPL application in conjunction with this file and SAMPLE.TXT to understand how an application is put together. FRAME.OPL is provided for advanced users only and you would not normally need to understand this code to put an application together. ---------------------------------------------------------------------- MESSAGES When running, the "fRun:" procedure generates MESSAGES in response to events from the SERIES 3 operating system. These are in three categories: KEYBOARD,TIMER and SYSTEM (see below). Each message has a number, which determines which Call-back Routine (supplied by the application programmer) gets invoked when that event occurs. When the call-back routine is invoked an integer parameter and a string parameter are set (the parameters are actually the global variables "fParm%" and "fParm$"). The call-back routine uses these parameters to decide what to do. Sixteen of the messages are "maskable" - unless these are enabled, the call-back routine will not be invoked. The message mask is set when "fRun:" is first started and can be changed subsequently by returning a message from a call-back routine. The mask is a bit-map with one bit set for each message to be enabled. This mask can be assembled by adding together the values given in the MESSAGE TABLE below. The message handler call-backs return a message number when complete. This will normally be either an error message (negative) or 0 (null message) or 100 (exit message). However, the routine can return any message, including user-defined ones. Care must be taken to avoid infinite loops such as would happen if a call-back routine returned its own message number. ---------------------------------------------------------------------- KEYBOARD MESSAGES There are seven keyboard messages: #4 is invoked when the user presses a hotkey (PSION key with a letter or +,-,/ or *, EG PSION-S). This message is rarely un-masked as there is a special mechanism for handling individual hotkeys. A special call-back can be provided for each hotkey used in the application. Hotkeys are enabled and disabled using the hotkey mask. This mask is set from a parameter when "fRun:" is started and can subsequently be changed by a call-back routine returning either message #130 or #131. If you use this mechanism, do NOT enable message #4 as the special call-backs will then not be invoked. #5 is invoked when the user makes a keystroke which generates a printable character such as "a", "A" or "*". This includes SPACE, but excludes ENTER and DELETE. #6 is invoked when the user presses one of the "Special" keys such as "up arrow" "ESC" "ENTER" etc. (see SPECIAL KEY TABLE below). #9 is invoked when the "MENU" key is pressed. The associated call-back would normally bring up a menu system and then return either message #0 or #4. In the latter case, the parameters would be set by the call-back to the hotkey of the selected option. The framework will then use the hotkey call-back to activate the option as if the hotkey had been pressed. #10 is invoked when the "HELP" key is pressed. #13 is invoked when the "MENU" key is pressed with the "Ctrl" modifier. On the Series 3a this is conventionally used to cycle through the three alternative types of status window. #14 is invoked when the Series 3a "Diamond" key is pressed. For all keyboard messages there is a special additional parameter in the global variable "fKmod%". This gives the modifier status at the time the key was pressed as per the OPL KMOD function. This is particularly useful for detecting shifted special keystrokes. ---------------------------------------------------------------------- TIMER MESSAGES There are two timers: one generates a message every minute and the other every second. Only one timer may be active at any time. The timers are started and stopped by masking and unmasking their respective messages in the usual way. They are synchronised with the Series-3 clock (i.e. the minute timer message happens just after the minutes have changed on the clock). The timers continue to run even if the application is in the background, however they stop when the SERIES-3 switches off. The message parameter shows how many units of time have been missed when the SERIES-3 was off, or was tied up with other things. For stopwatches and similar applications, the parameter should be added to an accumulator each time the message call-back is invoked. This is important, because the system does not guarantee that the message will happen every unit of time. Also, the call-back may be called with parameter equal to zero when the timer is synchronising and the call-back must cope with this. ---------------------------------------------------------------------- SYSTEM MESSAGES Messages #1 to #3 and #12 are system messages invoked when the operating system changes the state of the application. Normally they can be left masked as all normal house keeping is done by the framework. Message #11 is the "Nothing better to do" message. It is invoked when there is a gap in the stream of other messages just before the framework suspends the application to await the next message. Un-mask this to perform low-priority or background processing such as "lazy" screen updating. Message #15 is generated when the framework receives a signal from the operating system which it does not recognise. This happens when the application initiates an asynchronous I/O service. On completion, message #15 is generated. A good use of this facility is to detect the completion of playback of a sound file on the Series 3A. Messages #100 and above are not handled by the normal call-back mechanism but may be returned by call-back routines to cause the framework to take appropriate actions. For file-based applications, the "aOpen%:", "aCreate%" and "aClose%" call-backs must be provided. The framework handles externally driven file handling using these routines. For application driven file handling DO NOT call these call-backs directly, go through the framework by returning the appropriate messages. #101 should be returned to create a new file. #102 should be returned to open a file. In both cases, the file name should be in fParm$. Messages #129 to #131 can be returned to change the message and hotkey masks while the application is running. The new value of the message mask should be in fParm% and the new value of the hotkey mask in fParm$. #129 changes only the message mask, #130 only the hotkey mask and #131 changes both masks. ---------------------------------------------------------------------- APPLICATION SKELETON REM Start of skeleton application APP skull TYPE 3 :REM May be of any type See Programming Manual Cp.11 ENDA PROC skull: REM Global Data required by application LOADM "\OPO\FRAMELIB.OPO" :REM Load the Application Framework Code. REM Application initialisation code (prior to file opening) fAutoOff: :REM Enable auto switch-off for this application. fRun:($0100,"AB",0) :REM Run the application, Menu key and hotkeys REM PSION-A and PSION-B enabled. ENDP REM Application call-back routines REM Other application routines REM End of skeleton application ---------------------------------------------------------------------- MESSAGE TABLE Message fParm% fParm$ Mask Event ======= ====== ====== ==== ===== 0 - Null (Nothing happened) 1 $0001 Program was moved to foreground 2 $0002 Program was moved to background 3 $0004 Machine was switched on 4 keycode char $0008 Hot key was pressed 5 keycode char $0010 Printable character was entered 6 keycode $0020 Special key was pressed 7 seconds $0040 Seconds timer elapsed 8 minutes $0080 Minutes timer elapsed 9 $0100 Menu key was pressed 10 $0200 Help key was pressed 11 $0400 Nothing better to do 12 $0800 * The date changed (Series 3a only) 13 $1000 * Ctrl-Menu key was pressed 14 $2000 * Diamond Key was pressed (Series 3a only) 15 $4000 * Unrecognised Asynch Signal 16 app app $8000 Application maskable message 17-99 app app - Application non-maskable messages 100 - Exit from application 101 filename - Create a new file 102 filename - Open an existing file 129 mask - Change the message mask 130 mask - Change the hotkey mask 131 mask mask - Change both masks Message fParm% fParm$ Error ======= ====== ====== ===== -1 ERR ERR$ OPL System Error (Only if enabled) -2 filename Cannot create file -3 filename Cannot open file -4 filename Bad filename * These messages are new to this version, see the VERSION COMPATIBILITY section below. Hotkey Message Mask =================== The hotkey message mask is a string containing all the valid hotkeys (in any order). Each character in the string must be either an upper- case letter or a digit 1 to 4. The digits map onto the non alphabetic hotkeys as follows: 1 : [+]; 2 : [-]; 3 : [/]; 4 : [*] To use shifted hotkeys, a second string is used appended to the first and separated from it by an exclamation mark. Examples: "AF3" - Enables PSION-A; PSION-B and PSION-/. SHIFT is ignored. "AF3!" - As above, but SHIFTed hotkeys will not work. "AF3!3" - As above, but PSION-/ and PSION-SHIFT-/ are distinct. ---------------------------------------------------------------------- SPECIAL KEYCODE TABLE Values in fParm% Modifiers (added together in fKmod%) Key Code Key Code === ==== === ==== Esc 27 Shift $0002 Delete 8 Control $0004 Tab 9 PSION $0008 Enter 13 Caps Lock $0010 up 256 down 257 left 259 right 258 Home 262 End 263 PgDn 261 PgUp 260 Dial 803 ---------------------------------------------------------------------- CALLBACK ROUTINE RESTRICTIONS IMPORTANT: Call-back routines must not do keyboard handling or message handling themselves. The following keywords must NOT be used: BUSY; CMD$; GET; GET$; GETCMD$; GETEVENT; KEY; KEY$; KEYA; KEYC; KMOD; LOCK; MENU (use fMenu%: instead); SETNAME; STOP; TESTEVENT. The following keywords must be prefixed with fLock: and followed by fUnLock: : ALERT; DIALOG; EDIT; INPUT ---------------------------------------------------------------------- CALLBACK ROUTINES (Written by application programmer) aOpen%: Open a file and perform any per-file initialisation. aCreate%: Create a file and perform any per-file initialisation. aClose%: Perform any tidy-up and close the current file. These routines MUST be provided for type 2, 3 or 4 OPAs. aOpen%: and aCreate%: should return 0 if successful or an appropriate error code (-2, -3 or -4) otherwise. aClose%: should return zero on success or non-zero to abort. aClose%: may include a confirm dialogue if desired, this will be visible even for file changes initiated at the system level. aInit%: Initialisation Call-back. This routine is optional. If provided it is called once during initialisation. The main purpose is to configure custom messages ( see CUSTOMISATION AND INTERNATIONALISATION) aError%:(e%) Error handler. e% is the error number. This routine is optional, if provided it should return either 0 or 100, or pass the error back for handling by the default handler. aMh1%: Message handlers for messages 1-99 above. Should return 0, aMh99%: an error number or another message (NEVER the same message). These routines must be provided for all messages below 99 which are defined and can be unmasked during program execution. aHkA%: Hot Key handlers for keys A to Z. aHkZ%: aHkSA%: Hot Key handlers for keys A to Z with SHIFT. aHkSZ%: aHk1%: Hot Key handler for + key. aHk2%: Hot Key handler for - key. aHk3%: Hot Key handler for / key. aHk4%: Hot key handler for * key. aHkS1%: Hotkey handler for +,-,/ and * with SHIFT. aHkS4%: These routines must be provided for any Hot Keys which may be unmasked during program execution. They should return 0, an error number or another message. ---------------------------------------------------------------------- FRAMEWORK ROUTINES (Provided in library) fRun:(mesMsk%,hkMsk$,sysE%) This is the main routine for the Application Framework system. It is called from the application's main PROC and, on exiting the application run is complete. The parameters are: mesMsk%: Initial value of message mask. hkMsk$: Initial value of hotkey mask. sysE%: True (non zero) if system errors should be trapped. Call-back routines (or initialisation code) may themselves call the following framework routines: fMenu%: Use this routine in place of the OPL keyword MENU. It incorporates fLock: and fUnlock: below and also implements a PSION supplied fix for a bug in the MENU command. fLock: Use these before and after any command that waits for user fUnlock: keyboard activity I.E. a dialogue box or alert box. fAutoOff: Call this to allow the Series 3 to switch off when an application using timers is running. fVer%: Returns the version number of FRAMELIB.OPO. ---------------------------------------------------------------------- CUSTOMISATION AND INTERNATIONALISATION The framework has three text messages which are initialised to English Language defaults but which may be changed by any call-back routine. The most obvious place is in the aInit%: call-back. fBusyM$ - The text in the "Busy...." message flash. Default: "busy...." fTermM$ - The heading in the default error handler. Default: "TERMINAL ERROR" fStopM$ - The button label in the default error handler. Default: "Stop" These are simply global string variables: just set them to any desired string (20 characters or less). ---------------------------------------------------------------------- VERSION COMPATIBILITY Because this is a run-time code library which may be shared between more than one application, care must be taken with configuration control. Strenuous efforts have been made by the author to ensure backward compatibility is maintained between this version and previous versions and all code written according to the published interfaces should continue to work with this version. The framework procedure "fVer%:" returns the version number of the library and application programmers should insure that installation routines do not overwrite a later version of the library with an earlier. If applications depend on features of versions other than the first, they should test that the version is GREATER THAN OR EQUAL TO the first version that had all the required features. Do NOT test for a specific version number as the framework may be upgraded independently of your application. This version adds four new system messages which may conflict with user defined maskable messages in applications written for an earlier version. These messages are initially disabled to maintain compatibility. To use them, you must include an initialisation call-back as follows: PROC aInit%: fCompM%=$7800 Enables system messages 12,13,14 & 15 ENDP Note that the bit assignments in this mask are the same as in the main message mask, so, for example, $1000 enables message 13 only. ---------------------------------------------------------------------- MACHINE TYPE DIFFERENCES The only difference between the dual machine and the S3a only versions of the library is that the S3a version has been translated using the S3a translator which enables procedure caching to work with the framework procedures. Both versions use identical source code and the dual machine version will work fine on the S3a even if the application is translated for the S3a and uses the S3a screen hi-res screen mode. On an S3 machine, or an S3a when the application is in compatibility mode, some messages simply are not generated. The "Date Change" and "Diamond key" messages are examples. ---------------------------------------------------------------------- CONDITIONS OF USE The files FRAMELIB.OPO and FRAMELBA.OPO and the associated documentation and source code are provided as-is and the author will not be liable for any consequences of its use. The file FRAME.ZIP may be freely distributed so long as it is unchanged and complete. The files FRAMELIB.OPO and FRAMELBA.OPO may be freely distributed as part of an application as long as the documentation credits me for my contribution and a copy of the application is made available for my use free of charge. If an application using FRAMELIB.OPO is sold for profit, I request that a donation be made on my behalf to Amnesty International. I would appreciate any bug reports, comments, ideas or suggestions for the further development of this system. John Hind 1a Brunswick Quay, Redriff Road, London SE16 1PU, United Kingdom. CompuServe: 70374,756 END OF DOCUMENT ----------------------------------------------------------------------